package toy.keli.picmap.tools;

import android.app.Dialog;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.CountDownTimer;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.baidu.mapapi.animation.Animation;
import com.baidu.mapapi.animation.Transformation;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.BitmapDescriptor;
import com.baidu.mapapi.map.BitmapDescriptorFactory;
import com.baidu.mapapi.map.InfoWindow;
import com.baidu.mapapi.map.MapStatus;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.Marker;
import com.baidu.mapapi.map.MarkerOptions;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.model.LatLngBounds;
import com.baidu.mapsdkexample.geometry.markercluster.MyItem;

import java.util.ArrayList;
import java.util.List;

import toy.keli.picmap.BmapActivity;
import toy.keli.picmap.R;
import toy.keli.picmap.model.Model;
import toy.keli.picmap.model.def;
import toy.keli.picmap.model.event;
import toy.keli.picmap.model.pic;
import toy.keli.picmap.model.system;
import toy.keli.picmap.model.time;
import toy.keli.picmap.util.utilStore;

/**
 *
 */
public class Show {
    public static BmapActivity act;
    public static BaiduMap mBaiduMap;


    public interface IFunction{
        //    void call(T v,int i);
        void call();
    }
    public static void moveTo(double x, double y, float zoom){
        moveTo(x,y,zoom,100,()->{});
    }
    public static void moveTo(double x, double y, float zoom, int time){
        moveTo(x,y,zoom,time,()->{

        });
    }
    static void moveTo(double x, double y, float zoom, int time, IFunction func){
        MapStatus status = mBaiduMap.getMapStatus();
        double x0=(status.bound.northeast.longitude+status.bound.southwest.longitude)/2,
                y0=(status.bound.northeast.latitude+status.bound.southwest.latitude)/2,
                z0=status.zoom;
        int count=time/50;
        double xn=(x-x0)/count,yn=(y-y0)/count,zn=(zoom-z0)/count;
        double[] a={x0,y0,z0};
        double[] b={xn,yn,zn};

        CountDownTimer cdt = new CountDownTimer(time, 50) {
            @Override
            public void onTick(long millisUntilFinished) {
                a[0]+=b[0];a[1]+=b[1];a[2]+=b[2];
                LatLng center = new LatLng(a[1],a[0]);
                MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newLatLngZoom(center, (float)a[2]);
                mBaiduMap.setMapStatus(mapStatusUpdate);
            }
            @Override
            public void onFinish() {
                MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newLatLngZoom(new LatLng(y,x),zoom);
                mBaiduMap.setMapStatus(mapStatusUpdate);
                func.call();
            }
        };

        cdt.start();

    }

    public static void moveTo(double x, double y){
        moveTo(x,y,18,1000);
    }
    static void moveZoomTo(LatLng point, float zoom, IFunction func){
        moveTo(point.longitude,point.latitude, mBaiduMap.getMapStatus().zoom,500,()->{
            zoomTo(point,mBaiduMap.getMapStatus().zoom,zoom,func);
        });
    }
    public static void zoomTo(LatLng center, float level,IFunction finish){
        zoomTo(center,level-8,level,finish);
    }
    public static void zoomTo(LatLng center, float z,float level,IFunction finish){
        final float[] zoom = {z};
        MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newLatLngZoom(center, zoom[0]);
        mBaiduMap.setMapStatus(mapStatusUpdate);
        //Android中实现定时器  https://www.cnblogs.com/dame/p/8085983.html  , https://www.cnblogs.com/wansho/p/5104335.html
        int time= (int) ((level-z)*500);
        CountDownTimer cdt = new CountDownTimer(time, 50) {
            @Override
            public void onTick(long millisUntilFinished) {
                zoom[0]+=0.1;
                if(zoom[0]>3) {
                    MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newLatLngZoom(center, zoom[0]);
                    mBaiduMap.setMapStatus(mapStatusUpdate);
                }
            }
            @Override
            public void onFinish() {
                MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newLatLngZoom(center, level);
                mBaiduMap.setMapStatus(mapStatusUpdate);
                finish.call();
            }
        };

        cdt.start();
        //mBaiduMap.setMapStatus(mapStatusUpdate);
    }

    public static void openCity(String cityName) {
        Location.AddrToPoint(cityName,(point)->{
            //int cid=new OfflineMap().getCityIdByName(cityName);
            MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newLatLngZoom((LatLng) point, 12);
            mBaiduMap.setMapStatus(mapStatusUpdate);
        });
    }



    public static Bitmap toOvalBitmap(Bitmap bitmap, float ratio) {
        int w=bitmap.getWidth(),h=bitmap.getHeight();
        Bitmap output=Bitmap.createBitmap(h,w, Bitmap.Config.ARGB_8888);
        Canvas canvas=new Canvas(output);
        Paint paint=new Paint();
        Rect rect=new Rect(0,0,w,h);
        RectF rectF=new RectF(rect);

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        canvas.drawRoundRect(rectF, w/ratio,
                h/ratio, paint);

        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect,rectF, paint);
        return output;
    }
    public static void pointMove(LatLng start,LatLng end,int time,IFunction endfunc) {
        Transformation mTransforma = new Transformation(start,end);
        mTransforma.setDuration(time);
        //mTransforma.setRepeatCount(1);

        BitmapDescriptor mBitmapDescriptor = BitmapDescriptorFactory.fromResource(R.drawable.icon_mark);
        MarkerOptions markerOptions = new MarkerOptions()
                .position(start)
                .icon(mBitmapDescriptor);
        Marker mMarker = (Marker) mBaiduMap.addOverlay(markerOptions);

        mMarker.setAnimation(mTransforma);
        mMarker.startAnimation();
        //根据开发需要设置动画监听
        mTransforma.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationEnd() {
                mMarker.remove();
                endfunc.call();
            }
            @Override
            public void onAnimationStart() { }
            @Override
            public void onAnimationCancel() {}
            @Override
            public void onAnimationRepeat() {}
        });
    }

    static boolean pointIsShow(LatLng p){
        MapStatus status = mBaiduMap.getMapStatus();
        double[] x={status.bound.northeast.longitude,status.bound.southwest.longitude},
                y={status.bound.northeast.latitude,status.bound.southwest.latitude};
        return p.latitude<y[0] && p.latitude>y[1] && p.longitude<x[0] && p.longitude>x[1];
    }
    static void setBounds(ArrayList<LatLng> mLatLngs , int padding) {
        int paddingBottom=0;
        // 构造地理范围对象
        LatLngBounds.Builder builder = new LatLngBounds.Builder();
        // 让该地理范围包含一组地理位置坐标
        builder.include(mLatLngs);

        // 设置显示在指定相对于MapView的padding中的地图地理范围
        MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newLatLngBounds(builder.build(), padding, padding,padding, paddingBottom);
        // 更新地图
        mBaiduMap.setMapStatus(mapStatusUpdate);
        // 设置地图上控件与地图边界的距离，包含比例尺、缩放控件、logo、指南针的位置
        mBaiduMap.setViewPadding( 0 , 0 , 0 , paddingBottom);
    }

    static  void zoomInPoint(LatLng point,int maxT, IFunction o) {
            MapStatus status = mBaiduMap.getMapStatus();
            LatLng center = new LatLng((status.bound.southwest.latitude+status.bound.northeast.latitude)/2,(status.bound.northeast.longitude+status.bound.southwest.longitude)/2);
            final float[] zoom = {status.zoom};
            time.run(maxT,50,(i)->{
                MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newLatLngZoom(center, zoom[0] -=0.5);
                mBaiduMap.setMapStatus(mapStatusUpdate);
                return zoom[0]>3 && !pointIsShow(point);
            },()->{
                MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newLatLngZoom(center, zoom[0]-1);
                mBaiduMap.setMapStatus(mapStatusUpdate);
                o.call();
            });
    }

    //显示缩略图
    public static void thumbnail(MyItem item){
        mBaiduMap.showInfoWindow(getInfoWindow(item, item.getPic().getStringTime2()));
    }
    
    static InfoWindow getInfoWindow(MyItem item,String text) {
        View view=View.inflate(mBaiduMap.getGLMapView().getContext(), R.layout.pic_pop,null);
        pic p=(pic)Model.populateRecord(pic.class,item.data);
        ((TextView)view.findViewById(R.id.time)).setText(text);
        ImageView image = (ImageView) view.findViewById(R.id.img);
        View popBox =view.findViewById(R.id.pop_box);
        //popBox.setLayoutParams(new RecyclerView.LayoutParams(300,300));
        try {
            Bitmap bitMap = toOvalBitmap(p.thumbnail(300,300), 1f);
            image.setImageBitmap(bitMap);
            image.setScaleType(ImageView.ScaleType.MATRIX);
        }catch (Exception e){e.printStackTrace(); return null;}

        image.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                act.openPic(p.id);
                mBaiduMap.hideInfoWindow();
            }
        });
        image.setOnLongClickListener(new View.OnLongClickListener(){
            @Override
            public boolean onLongClick(View v) {
                time tnow = new time(p.intime);
                String[] a={"同天","同周","同月","同季","同年","收藏"};
                act.popupMenu(v,a,(i)->{
                    if(i.equals("收藏")){
                        def  bookmark= utilStore.name("bookmark");
                        if(!bookmark.exists(p.id)) {
                            bookmark.push(p.id);
                            act.msg("收藏成功");
                        }else {
                            act.msg("已经收藏了");
                        }
                        return;
                    }
                    Control.date=tnow.sameLimit(i);
                    List<MyItem> items = act.getFilter().runByDate();
                });
                return true;
            }
        });

        InfoWindow iw = new InfoWindow(view, item.getPosition(), -110);
        return iw;
    }

    static timeAnimation timeAnimationObj;
    public static void clearTimeAnimation(){
        timeAnimationObj.taRuning=false;
        timeAnimationObj=null;
        act.getProgressBar().progresUpdate(-1,0,"");
        act.setmButtonIco("+");
        mBaiduMap.hideInfoWindow();
    }
    public static timeAnimation getTimeAnimation(){
        return getTimeAnimation(true);
    }
    public static timeAnimation getTimeAnimation(boolean autoCreate){
        if(timeAnimationObj==null && autoCreate) {
            if(Control.date.length==0 || Control.date[0]==0){
                time t=new time();
                Control.date = new long[]{t.getTime("yyyy-MM-dd"), t.getTime(), -1};
                act.getFilter().runByDate();
            }
            timeAnimationObj=new timeAnimation(act.mItemsFilter,Control.taNextTime);
            timeAnimationObj.setTaRuning(false);
        }
        //只有小于季度的可以触发动画效果　
        if(Control.date[2]>-1) return null;
        return timeAnimationObj;
    }
    public static void timeAnimationTo(int i) {
        int tmp = Control.taNextTime;  Control.taNextTime=0;        //关闭动画
        boolean taEnable = Control.taEnable;
        getTimeAnimation();
        timeAnimationObj.setTaRuning(false);
        timeAnimationObj.toIndex(timeAnimationObj.taIndex=i);
        Control.taNextTime=tmp;
        if(taEnable) {
            time.Out(tmp,()->{
                timeAnimationObj.next();
            });
        }
    }
    /**
     * 时间动画
     */
    public static class timeAnimation {
        ArrayList<LatLng> mLatLngs = new ArrayList<>();
        boolean taRuning = false;
        List<MyItem> taItems;
        int taType = 0; //０张（天）1周 2月　3季 4年
        int taSize = 0;
        int taIndex = 0;
        int taTime=2000;
        Dialog mDialog;
        MyItem taItem;
        MapStatusUpdate taMapStatusUpdate;

        public void setTaRuning(boolean taRuning) {
            this.taRuning = taRuning;
        }

        public boolean toggleTaRuning(){
            taRuning = !taRuning;
            Control.setTaEnable(taRuning,act);
            if(taRuning) next();
            act.keepScreenOn(taRuning);
            //act.getProgressBar().progresUpdate(0, 0, taRuning ? "start..": "over!");
            return taRuning;
        }
        public void next() {
            if(!Control.taEnable) return;
            if(taIndex>taSize) {
                mBaiduMap.setMapStatus(taMapStatusUpdate);
                taRuning = false;
                taIndex=0;
                act.getProgressBar().progresUpdate(-1, taSize, "over!");
                act.keepScreenOn(taRuning);
                mBaiduMap.hideInfoWindow();
                Control.setTaEnable(taRuning,act);
            }

            if(taRuning) toIndex(taIndex++);
        }
        void setBoxSize(View popBox,int size){
            ImageView image = popBox.findViewById(R.id.img);
            ViewGroup.LayoutParams layoutParams = popBox.getLayoutParams();
            layoutParams.width= layoutParams.height=size;
            Matrix m = image.getImageMatrix();
            float sc=(float)layoutParams.width/image.getWidth();
            m.postScale(sc,sc);
            Log.d("kdebug","s:"+size);
            image.setImageMatrix(m);
            popBox.setLayoutParams(layoutParams);
        }

        /**
         * 图片缩略图慢慢变大的显示效果
         * @param iw
         * @param o
         */
        void wShow(InfoWindow iw,IFunction o){
            if(iw==null) return;
            //mBaiduMap.showInfoWindow(iw);
            View popBox =iw.getView().findViewById(R.id.pop_box);
            //动画间隔事件小于500 直接调用系统函数定时执行回调
            if(taTime<500) {
                time.Out(taTime,()->{o.call();});
                return;
            }
            //50ms执行一次图片放大操作, 到2s的时候执行缩小操作
            time.run(taTime,50,(i)->{
                i+=1;
                if(i<15) {
                    int size=300+i*30;
                    setBoxSize(popBox,size);
                }else if(mDialog==null){
                    ImageView img = new ImageView(act);
                    Point size = system.getScreenSize(act);
                    Bitmap bmp = taItem.getPic().thumbnail(0, size.y);
                    img.setImageBitmap(bmp);
                    img.setBackgroundColor(Color.parseColor("#000000"));
                    img.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {   //单击暂停或开始
                            toggleTaRuning();
                            if(!taRuning) act.openPic(taItem.id);
                        }
                    });
                  //  mBaiduMap.showInfoWindow(new InfoWindow(img, new LatLng(0,0),0));
                    mDialog=new Dialog(act);

//                        ImageView image = (ImageView) popBox.findViewById(R.id.img);
//                        img.setImageBitmap(bmp);
//                        mDialog = act.simpDialog(img);
                   //     popBox.setVisibility(View.GONE);
                }
                return taRuning;
            },()->{
                if(mDialog!=null) mDialog.hide();
                mDialog=null;
                //mBaiduMap.showInfoWindow(iw);
                popBox.setVisibility(View.VISIBLE);
                //执行缩小操作
                time.run(750,50,(j)-> {
                    int size  = (16 - j) * 50;
                    setBoxSize(popBox,size);
                    return size > 300 && taRuning;
                },()->{
                    o.call();
                });
            });
        }

        //移动并显示图片
        void moveAndShow(InfoWindow iw){
            mBaiduMap.showInfoWindow(iw);
            if(mLatLngs.size()==1)
                wShow(iw,()->{next(); });
            else
                pointMove(mLatLngs.get(mLatLngs.size() - 2), mLatLngs.get(mLatLngs.size() - 1), taTime,()->{
                    wShow(iw,()->{next(); });
                });
        }

        ////图片显示,moveAndShow函数来触发下一次调用
        void openPointInfo(MyItem item,boolean showDay) {
            taItem=item;
            LatLng point = item.getPosition();
            //缩略图上显示的内容构建
            String text=new time(item.getData().get("intime").toLong()).format(showDay ? "yyyy.MM.dd HH:mm": "HH:mm");
            InfoWindow iw = getInfoWindow(item, text);
            //停止动画时还原状态并返回
            if(Control.taNextTime==0) {
                MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newLatLngZoom(point, mBaiduMap.getMapStatus().zoom);
                mBaiduMap.setMapStatus(mapStatusUpdate);
                mBaiduMap.showInfoWindow(iw);
                return;
            }

            mLatLngs.add(point);
            if(mLatLngs.size()>5) mLatLngs.remove(0);
            mBaiduMap.hideInfoWindow();
            //不能显示这个点了缩小比例尺 到能显示为止
            if(!pointIsShow(point)){
                //setBounds(mLatLngs,200);
                //mBaiduMap.showInfoWindow(iw);
                zoomInPoint(point,taTime,()->{
                    moveZoomTo(point,18,()->{
                        moveAndShow(iw);
                    });
                });
            //比例尺太大 放大显示 移动这个点到屏幕中间
            }else if(mBaiduMap.getMapStatus().zoom<18){
                //zoomTo(point,mBaiduMap.getMapStatus().zoom,18,taTime,()->{
                moveZoomTo(point,18,()->{
                    moveAndShow(iw);
                });
            //下一个点在屏幕里直接显示这个点
            }else{
                moveAndShow(iw);
            }
        }

        //时间动画构造函数(无参)
        public timeAnimation() {
            long size = 0;
            taType= (int) Control.date[2];
            switch (taType) {
                case 4:    //年
                    size = pic.getCount("year");
                    break;
                case 3: //季度
                    size=4;
                    break;
                case 2: //月份
                    size=new time().formatInt("MM");
                    break;
                case 1: //周　
                    size = new time().formatInt("w");
                    break;
                case 0: //天
                   size=(Control.date[1]-Control.date[0])/86400000;

                   break;
                default:
                    List<MyItem> items = act.getFilter().runByDate();
                    new timeAnimation(items,Control.taNextTime);
                    return;
            }

            taSize = (int)size;
            timeAnimationObj=this;
            taIndex=taType==0? 0:taSize;
            act.getProgressBar().progresUpdate(taIndex, taSize, "");
            toIndex(taIndex);
        }

        /**
         * 时间动画 构造函数带参数形式
         * @param mItems
         * @param t
         */
        public timeAnimation(List<MyItem> mItems, int t) {
            if(timeAnimationObj!=null) {
                clearTimeAnimation();
            }
            mLatLngs.clear();
            timeAnimationObj=this;
            //获取当前地图位置动画结束后还原这个位置
            taMapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mBaiduMap.getMapStatus());
            //动画的基本参数配置
            int size =mItems.size();
            taType= (int) Control.date[2];
            taItems = mItems;
            taSize = size;
            taIndex = taType<0? 0: size;
            taTime=t;
            taRuning = true;
            //保持屏幕常亮
            act.keepScreenOn(taRuning);
            //进度条展示
            act.getProgressBar().progresUpdate(taIndex, size, "");
            //界面按钮的图标转换
            Control.setTaEnable(taRuning,act);
            //开始动画
            toIndex(taIndex);
        }

        //单张动画
        public void toIndex0(int i) {
            try {
                MyItem p = taItems.get(taSize - i);
                openPointInfo(p, false);
                String title=new time(p.getData().get("intime").toLong()).format("yyyy.MM.dd HH:mm");
                act.getProgressBar().progresUpdate(i, 0, title);
            }catch (Exception e){
                e.printStackTrace();
                next();
            }
        }
        public void toIndex(int i) {
            Log.d("kdebug", new time().format("mm:ss") + " @" + i);
            boolean showDay = false;
            String title="";
            time t = Control.date[0]>0 ? new time(Control.date[0]): new time();
            //0张 1月 2周 3天 4时
            switch (taType) {
                case 0:  //天　
                    long start=Control.date[0] + i * 86400000;
                    taItems = act.getFilter().runByDate(start, 0);
                    title=t.set(start).format("yyyy年 MM月dd日("+taItems.size()+"张)");
                    act.getStatusbar().setText(title);
                    return;
                case 1: //周
                    t.setWeek(i);
                    title=t.format("yyyy年第w周 MM月dd日开始");
                    Control.setDate(t.getTime(),t.next("week").getTime());
                    break;
                case 2: //月
                    t.setMonth(i-1);
                    title=t.format("yyyy年MM月");
                    t.setTime(t.getTime("yyyy-MM"));
                    Control.setDate(t.getTime(),t.next("mouth").getTime());
                    break;
                case 3: //季度
                    t.setSeason(i);
                    title=t.format("yyyy年")+t.getSeasonName();
                    Control.setDate(t.getTime(),t.next("season").getTime());
                    break;
                case 4: //年
                    t.setYear(new time().getYear()-(taSize-i));
                    title= t.format("yyyy年");
                    t.setTime(t.getTime("yyyy"));
                    Control.setDate(t.getTime(),t.next("year").getTime());
                    break;
                case -1:
                default:
                    toIndex0(i);
                    return;
            }

            act.getFilter().runByDate();
            //act.getProgressBar().progresUpdate(i, 0, title);
            act.getStatusbar().setText(title);
        }
    }

    public static void onEvent(event.type t) {
        long t0 = Control.date[1],t2=Control.date[2];
        int dType=(int)t2;
        String tname=Control.getDateType();
        time tt = new time();
        tt.setTime(t0);
        timeAnimation ta = getTimeAnimation(false);
        int index = ta.taIndex;
        switch (t){
            case LEFT:
                Control.setDate(tt.next(tname,-1).getTime(),t0,dType);
                index--;
                break;
            case RIGHT:
                Control.setDate(tt.next(tname,1).getTime(),tt.next(tname,1).getTime(),dType);
                index++;
                break;
            case UP:
                dType=Math.max(1,Math.min(4,(int)t2+1));
                tname=Control.getDateType(dType);
                Control.setDate(tt.next(tname,0).getTime(),tt.next(tname,1).getTime(),dType);
                break;
            case DOWN:
                dType=Math.max(0,(int)t2-1);
                tname=Control.getDateType(dType);
                Control.setDate(tt.next(tname,0).getTime(),tt.next(tname,1).getTime(),dType);
                break;
            case CLICK:
                return;
//                if(dType>=0) {          //天周月季年
//                    int[] tMap=new int[]{0,0,2,2,4};
//                    dType=(int)t2-1;
//                    Control.setDateType(dType>=0 ? dType = tMap[dType]: -1);
//                }else {
//                    getTimeAnimation().toggleTaRuning();
//                    return;
//                }
//                break;
            default:
                return;
        }
        if(t2!=dType){
            if(dType==-1){
                ta=new timeAnimation(ta.taItems,Control.taNextTime);
            }else
                ta = new timeAnimation();
        }
        else ta.toIndex(index);
        if(dType>=0) act.setmButtonIco(Control.getDateTypeName());
    }
}
